package world.snowcrystal.service.Impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import world.snowcrystal.dao.UserDisplayDetails;
import world.snowcrystal.exception.SnowcrystalAlreadyExistException;
import world.snowcrystal.exception.SnowcrystalOperationFailedException;
import world.snowcrystal.exception.SnowcrystalUserNotFoundException;
import world.snowcrystal.mapper.UserAuthenticationDetailsMapper;
import world.snowcrystal.mapper.UserDisplayDetailsMapper;
import world.snowcrystal.properties.OssProperties;
import world.snowcrystal.service.UserService;

import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

@Service("userService")
@ConditionalOnMissingClass("userService")
//@ConditionalOnClass({OSS.class, OSSClient.class, UserDisplayDetails.class, UserAuthenticationDetails.class})
public class DefaultUserService implements UserService {

    @Autowired
    private UserDisplayDetailsMapper displayDetailsMapper;

    @Autowired
    private UserAuthenticationDetailsMapper userAuthenticationDetailsMapper;

    @Autowired
    private OSS ossClient;

    @Autowired
    private OssProperties properties;

    @Override
    @Transactional
    public void uploadDisplayInfo(UserDisplayDetails userDisplayDetails) {
        Assert.notNull(userDisplayDetails, "UserDisplayDetails must not be null");
        displayDetailsMapper.insertOrUpdate(userDisplayDetails);
    }

    /**
     * 将图像上传至 OSS 服务器，并返还文件的 URL；
     * 之后需要将这个 URL 保存到实体类中保存到 DB。
     * 如果 DB 操作异常，则这个操作需要进行回滚
     *
     * @param avatarFile 文件输入流
     * @param mimeType   文件的MIME 类型，比如 <code>image/jpeg</code>
     * @return 文件的 URL
     * @throws OSSException 与 OSS 操作相关的异常
     * @see OSS#putObject(PutObjectRequest) putObject
     */
    @Override
    public String uploadAvatar(InputStream avatarFile, String mimeType)
            throws OSSException {
        String key = null;
        try {
            MessageDigest instance = MessageDigest.getInstance("MD5");
            byte[] digest = instance.digest(avatarFile.readAllBytes());
            key = Base64.getEncoder().encodeToString(digest);
        } catch (NoSuchAlgorithmException ignore) {
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        ObjectMetadata metadata = new ObjectMetadata();
        PutObjectRequest request = new PutObjectRequest(properties.getBucketName(), key, avatarFile);
        metadata.setContentType(mimeType);
        metadata.setContentMD5(key);
        request.setMetadata(metadata);
        PutObjectResult result = ossClient.putObject(request);
        return result.getResponse().getUri();
    }

    @Override
    public UserDisplayDetails retrieveDisplayInfo(Integer id) {

        UserDisplayDetails udd = new UserDisplayDetails();

        try{
            udd = displayDetailsMapper.selectOne(new QueryWrapper<>(udd)
                    .checkSqlInjection()
                    .eq("id",id)
            ,true);
        }catch (Exception e){
                throw new SnowcrystalUserNotFoundException("user with id " + id + " not found");
        }

        return udd;
    }

    @Override
    public UserDisplayDetails retrieveUserDisplayInfo(String username) {
        UserDisplayDetails udd = new UserDisplayDetails();
        try{
            udd = displayDetailsMapper.selectOne(new QueryWrapper<>(udd)
                    .checkSqlInjection()
                    .eq("username",username),true);
        }catch (Exception e){
            throw new SnowcrystalUserNotFoundException("user with name " + username + " not found");
        }
        return udd;
    }

    /**
     * 检查这个邮箱是否已经存在
     *
     * @param mail 待检测邮箱
     * @return true 如果邮箱不存在于数据库中
     * @author tianqing
     * @since 1.0
     */
    @Override
    public boolean checkIfMailAbsent(String mail) {
        UserDisplayDetails userDisplayDetails = displayDetailsMapper.selectOne(new QueryWrapper<UserDisplayDetails>()
                .checkSqlInjection()
                .select("id")
                .eq("email", mail));
        return userDisplayDetails == null;
    }

    /**
     * 更新用户名
     *
     */
    @Override
    @Transactional
    public void updateUsername(Long id, String username)
            throws SnowcrystalOperationFailedException, SnowcrystalAlreadyExistException {
        UserDisplayDetails userDisplayDetails = displayDetailsMapper.selectOne(new QueryWrapper<UserDisplayDetails>()
                .checkSqlInjection()
                .select("id")
                .eq("username", username));
        if(userDisplayDetails != null){
            if(!id.equals(userDisplayDetails.getId())){
                throw new SnowcrystalAlreadyExistException("用户名已经存在了哦");
            }else{
                return;
            }
        }

        int update = displayDetailsMapper.update(new UpdateWrapper<UserDisplayDetails>()
                .checkSqlInjection()
                .set("username", username)
                .eq("id", id)
        );
        if (update != 1) {
            throw new SnowcrystalOperationFailedException("操作失败");
        }
    }
}
